package health_system.health_system.repository;

import health_system.health_system.entity.Friendship;
import health_system.health_system.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface FriendshipRepository extends JpaRepository<Friendship, Long> {
    
    // Find friendship between two users
    @Query("SELECT f FROM Friendship f WHERE (f.requester = :user1 AND f.addressee = :user2) OR (f.requester = :user2 AND f.addressee = :user1)")
    Optional<Friendship> findFriendshipBetweenUsers(@Param("user1") User user1, @Param("user2") User user2);
    
    // Find all friendships for a user (both requester and addressee)
    @Query("SELECT f FROM Friendship f WHERE f.requester = :user OR f.addressee = :user")
    List<Friendship> findAllFriendshipsByUser(@Param("user") User user);
    
    // Find all accepted friendships for a user
    @Query("SELECT f FROM Friendship f WHERE (f.requester = :user OR f.addressee = :user) AND f.status = 'ACCEPTED'")
    List<Friendship> findAcceptedFriendshipsByUser(@Param("user") User user);
    
    // Find all accepted friendships with pagination
    @Query("SELECT f FROM Friendship f WHERE (f.requester = :user OR f.addressee = :user) AND f.status = 'ACCEPTED'")
    Page<Friendship> findAcceptedFriendshipsByUser(@Param("user") User user, Pageable pageable);
    
    // Find pending friend requests received by a user
    @Query("SELECT f FROM Friendship f WHERE f.addressee = :user AND f.status = 'PENDING'")
    List<Friendship> findPendingFriendRequestsForUser(@Param("user") User user);
    
    // Find friend requests sent by a user
    @Query("SELECT f FROM Friendship f WHERE f.requester = :user AND f.status = 'PENDING'")
    List<Friendship> findSentFriendRequestsByUser(@Param("user") User user);
    
    // Find accepted friend addressees for a user
    @Query("SELECT f.addressee FROM Friendship f WHERE f.requester = :user AND f.status = 'ACCEPTED'")
    List<User> findAcceptedRecipientsByRequester(@Param("user") User user);
    
    // Find accepted friend requesters for a user
    @Query("SELECT f.requester FROM Friendship f WHERE f.addressee = :user AND f.status = 'ACCEPTED'")
    List<User> findAcceptedRequestersByRecipient(@Param("user") User user);
    
    // Check if two users are friends
    @Query("SELECT CASE WHEN COUNT(f) > 0 THEN true ELSE false END FROM Friendship f " +
           "WHERE ((f.requester = :user1 AND f.addressee = :user2) OR (f.requester = :user2 AND f.addressee = :user1)) " +
           "AND f.status = 'ACCEPTED'")
    boolean areFriends(@Param("user1") User user1, @Param("user2") User user2);
    
    // Update friendship status
    @Modifying
    @Query("UPDATE Friendship f SET f.status = :status WHERE f.id = :id")
    void updateFriendshipStatus(@Param("id") Long id, @Param("status") Friendship.FriendshipStatus status);
    
    // Count friends for a user
    @Query("SELECT COUNT(f) FROM Friendship f WHERE (f.requester = :user OR f.addressee = :user) AND f.status = 'ACCEPTED'")
    Long countFriendsByUser(@Param("user") User user);
    
    // Find blocked relationships
    @Query("SELECT f FROM Friendship f WHERE (f.requester = :user OR f.addressee = :user) AND f.status = 'BLOCKED'")
    List<Friendship> findBlockedRelationshipsByUser(@Param("user") User user);
    
    // Find friendships by friend circle
    @Query("SELECT f FROM Friendship f WHERE ((f.requester = :user OR f.addressee = :user) AND f.status = 'ACCEPTED') AND f.friendCircle = :circleName")
    List<Friendship> findFriendshipsByCircle(@Param("user") User user, @Param("circleName") String circleName);
    
    // Find friends by friend circle
    @Query("SELECT CASE WHEN f.requester = :user THEN f.addressee ELSE f.requester END " +
           "FROM Friendship f WHERE (f.requester = :user OR f.addressee = :user) AND f.status = 'ACCEPTED' AND f.friendCircle = :circleName")
    List<User> findFriendsByCircle(@Param("user") User user, @Param("circleName") String circleName);
    
    // Find all friend circles for a user
    @Query("SELECT DISTINCT f.friendCircle FROM Friendship f WHERE (f.requester = :user OR f.addressee = :user) AND f.status = 'ACCEPTED' AND f.friendCircle IS NOT NULL")
    List<String> findAllFriendCirclesByUser(@Param("user") User user);
    
    // Count friends in a circle
    @Query("SELECT COUNT(f) FROM Friendship f WHERE (f.requester = :user OR f.addressee = :user) AND f.status = 'ACCEPTED' AND f.friendCircle = :circleName")
    Long countFriendsInCircle(@Param("user") User user, @Param("circleName") String circleName);
    
    // Update friend circle for a friendship
    @Modifying
    @Query("UPDATE Friendship f SET f.friendCircle = :circleName WHERE f.id = :id")
    void updateFriendCircle(@Param("id") Long id, @Param("circleName") String circleName);
    
    // Search friends by name
    @Query("SELECT CASE WHEN f.requester = :user THEN f.addressee ELSE f.requester END " +
           "FROM Friendship f WHERE (f.requester = :user OR f.addressee = :user) AND f.status = 'ACCEPTED' " +
           "AND (CASE WHEN f.requester = :user THEN f.addressee.fullName ELSE f.requester.fullName END) LIKE %:searchTerm%")
    List<User> searchFriendsByName(@Param("user") User user, @Param("searchTerm") String searchTerm);
    
    // Find possible mutual friends (friends of friends who are not direct friends)
    @Query("SELECT DISTINCT u FROM User u WHERE u NOT IN " +
           "(SELECT CASE WHEN f.requester = :user THEN f.addressee ELSE f.requester END " +
           "FROM Friendship f WHERE (f.requester = :user OR f.addressee = :user) AND f.status = 'ACCEPTED') " +
           "AND u != :user " +
           "AND EXISTS (SELECT 1 FROM Friendship f1, Friendship f2 WHERE " +
           "f1.status = 'ACCEPTED' AND f2.status = 'ACCEPTED' AND " +
           "((f1.requester = :user AND f1.addressee = f2.requester AND f2.addressee = u) OR " +
           "(f1.requester = :user AND f1.addressee = f2.addressee AND f2.requester = u) OR " +
           "(f1.addressee = :user AND f1.requester = f2.requester AND f2.addressee = u) OR " +
           "(f1.addressee = :user AND f1.requester = f2.addressee AND f2.requester = u)))")
    List<User> findPossibleMutualFriends(@Param("user") User user);
} 